package com.cuixichang.minimalism.domain;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cuixichang.minimalism.acl.RelevanceDesign;
import com.cuixichang.minimalism.basal.cnstants.DefaultValues;
import com.cuixichang.minimalism.basal.enums.DefaultNumberEnum;
import com.cuixichang.minimalism.core.mybatis.cnstants.BaseFieldNames;
import com.cuixichang.minimalism.core.security.core.specials.SecurityQuantity;
import com.cuixichang.minimalism.core.security.userdetails.CredentialDetail;
import com.cuixichang.minimalism.service.ILoginRoleService;
import com.cuixichang.minimalism.service.IMenuService;
import com.cuixichang.minimalism.service.IRoleMenuService;
import com.cuixichang.minimalism.service.IRoleService;
import com.cuixichang.minimalism.transfer.dto.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class IMenuCommandServiceImpl implements IMenuCommandService{

    @Autowired
    private IMenuService iMenuService;
    @Autowired
    private RelevanceDesign relevanceDesign;
    @Autowired
    private IRoleCommandService roleCommandService;
    @Autowired
    private IRoleMenuService roleMenuService;
    @Autowired
    private ILoginRoleService iLoginRoleService;
    @Autowired
    private IRoleService iRoleService;
    @Override
    public IMenuDTO selectByIdHasPreCheck(Long id, String systemCode, CredentialDetail credentialDetail) {
        Assert.notNull(id,"菜单Id不能为空,请检查");
       return Optional.ofNullable(credentialDetail).map(credential -> {
           return iMenuService.selectList(IMenuDTO.builder().build(), (menu, queryWrapper) -> {
                queryWrapper.eq(BaseFieldNames.ID,id);
                  List<Long> beAuthLoginIds = relevanceDesign.beAuthLoginIds(credential.getLoginId());
                  queryWrapper.in(!CollectionUtils.isEmpty(beAuthLoginIds), BaseFieldNames.CREATE_LOGIN_ID, beAuthLoginIds);
            }).stream().findFirst().orElse(null);
        }).orElse(iMenuService.selectById(id));
    }

    @Override
    public boolean deleteById(Long id, String systemCode, CredentialDetail credentialDetail) {
        Assert.notNull(id,"菜单Id不能为空,请检查");
        Boolean deleteStatus = Optional.ofNullable(credentialDetail).map(credential -> {
            return iMenuService.deleteByCondition(IMenuDTO.builder().createSystemCode(systemCode).build(), (menu, queryWrapper) -> {
                queryWrapper.eq(BaseFieldNames.ID, id);
                List<Long> beAuthLoginIds = relevanceDesign.beAuthLoginIds(credential.getLoginId());
                queryWrapper.in(!CollectionUtils.isEmpty(beAuthLoginIds), BaseFieldNames.CREATE_LOGIN_ID, beAuthLoginIds);
            }) == 1;
        }).orElseGet(() -> iMenuService.deleteById(id) == 1);
        if(deleteStatus) roleMenuService.deleteByCondition(IRoleMenuDTO.builder().menuId(id).build());
        return deleteStatus;
    }

    @Override
    public boolean updateById(IMenuDTO menuDTO, CredentialDetail credentialDetail) {
        Assert.notNull(menuDTO,"参数为空,请检查");
        Long id = menuDTO.getId();
        Assert.notNull(id,"菜单Id不能为空");
        menuDTO.setCreateLoginId(Objects.nonNull(credentialDetail)? credentialDetail.getLoginId(): DefaultNumberEnum.Zero.getCode());
        return iMenuService.updateById(menuDTO, (menu, queryWrapper) -> {
            if (Objects.nonNull(credentialDetail)) {
                List<Long> beAuthLoginIds = relevanceDesign.beAuthLoginIds(credentialDetail.getLoginId());
                queryWrapper.in(!CollectionUtils.isEmpty(beAuthLoginIds), BaseFieldNames.CREATE_LOGIN_ID, beAuthLoginIds);
            }
            queryWrapper.eq(Objects.nonNull(menu.getCreateSystemCode()),"create_system_code",menu.getCreateSystemCode());
        }) == 1;
    }

    @Override
    public Page<IMenuDTO> searchPageByConditional(IMenuDTO menuDTO, Long pageNo, Long pageSize, CredentialDetail credentialDetail) {
        Assert.notNull(menuDTO,"参数为空,请检查");
        Assert.notNull(pageNo,"页码不能为空");
        Assert.notNull(pageSize,"每页数量不能为空");
        Page<IMenuDTO> result = new Page<>(pageNo,pageSize);
        if(Objects.nonNull(credentialDetail)){
            List<Long> beAuthLoginIds = relevanceDesign.beAuthLoginIds(credentialDetail.getLoginId());
            result = iMenuService.selectPage(menuDTO, pageSize, pageNo, (menu, queryWrapper)->{
                   queryWrapper.in(!CollectionUtils.isEmpty(beAuthLoginIds), BaseFieldNames.CREATE_LOGIN_ID, beAuthLoginIds);
                String keyword = menuDTO.getKeyword();
                if(StrUtil.isNotBlank(keyword)){
                    queryWrapper.and(warp->{
                        warp.like("menu_name",keyword).or().like("menu_alias",keyword);
                    });
                }
            });
        }
        return result;
    }

    @Override
    public Page<IMenuDTO> roleHasBindingMenus(IMenuDTO menuDTO, Long pageNo, Long pageSize, Long roleId, CredentialDetail credentialDetail) {
        checkPageQuery(menuDTO, pageNo, pageSize);
        Assert.notNull(roleId,"查询角色Id为空,请检查");
        IRoleDTO role = Optional.ofNullable(credentialDetail).map(credential -> {
            List<Long> beAuthLoginIds = relevanceDesign.beAuthLoginIds(credential.getLoginId());
            List<ILoginRoleDTO> iLoginRoles = iLoginRoleService.selectList(ILoginRoleDTO.builder().loginId(credential.getLoginId()).build());
            return iRoleService.selectList(IRoleDTO.builder().createSystemCode(menuDTO.getCreateSystemCode()).build(), (iRole, queryWrapper) -> {
                queryWrapper.eq(BaseFieldNames.ID, roleId);
                //绑定的角色 + 创建的角色
                queryWrapper.and(wrapper -> {
                    wrapper.in(BaseFieldNames.CREATE_LOGIN_ID, beAuthLoginIds);
                    wrapper.or().in(!CollectionUtils.isEmpty(iLoginRoles), BaseFieldNames.ID, iLoginRoles.stream().map(ILoginRoleDTO::getRoleId)
                            .distinct().collect(Collectors.toList()));
                });
            }).stream().findFirst().orElse(null);
        }).orElse(iRoleService.selectById(roleId));
        Page<IMenuDTO> result = new Page<>(pageNo,pageSize);
        if(Objects.isNull(role)) return result;
        List<IRoleMenuDTO> iRoleMenus = roleMenuService.selectList(IRoleMenuDTO.builder().roleId(role.getId()).isEnable(true).build());
        List<Long> menuIds = iRoleMenus.stream().map(IRoleMenuDTO::getMenuId).distinct().collect(Collectors.toList());
        if(CollectionUtils.isEmpty(menuIds)) return result;
        return iMenuService.selectPage(menuDTO,pageSize,pageNo,(iMenu, queryWrapper) -> {
            queryWrapper.in(BaseFieldNames.ID,menuIds);
            String keyword = menuDTO.getKeyword();
            queryWrapper.and(StrUtil.isNotBlank(keyword),(wrapper)->{
                wrapper.like("menu_name",keyword);
                wrapper.or().like("menu_alias",keyword);
            });
        });
    }

    @Override
    public Page<IMenuDTO> roleUnBindingMenus(IMenuDTO menuDTO, Long pageNo, Long pageSize, Long roleId, CredentialDetail credentialDetail) {
        checkPageQuery(menuDTO, pageNo, pageSize);
        Assert.notNull(roleId,"查询角色Id为空,请检查");
        checkPageQuery(menuDTO, pageNo, pageSize);
        Assert.notNull(roleId,"查询角色Id为空,请检查");
        Page<IMenuDTO> result = new Page(pageNo,pageSize);
        return Optional.ofNullable(credentialDetail).map(credential -> {
            List<Long> beAuthLoginIds = relevanceDesign.beAuthLoginIds(credential.getLoginId());
            List<ILoginRoleDTO> iLoginRoles = iLoginRoleService.selectList(ILoginRoleDTO.builder().loginId(credential.getLoginId()).build());
            IRoleDTO role = iRoleService.selectList(IRoleDTO.builder().createSystemCode(menuDTO.getCreateSystemCode()).build(), (iRole, queryWrapper) -> {
                queryWrapper.eq(BaseFieldNames.ID, roleId);
                //绑定的角色 + 创建的角色
                queryWrapper.and(wrapper -> {
                    wrapper.in(BaseFieldNames.CREATE_LOGIN_ID, beAuthLoginIds);
                    wrapper.or().in(!CollectionUtils.isEmpty(iLoginRoles), BaseFieldNames.ID, iLoginRoles.stream().map(ILoginRoleDTO::getRoleId)
                            .distinct().collect(Collectors.toList()));
                });
            }).stream().findFirst().orElse(null);
            if(Objects.isNull(role)) return result;
            List<IRoleMenuDTO> iRoleMenus = roleMenuService.selectList(IRoleMenuDTO.builder().roleId(role.getId()).isEnable(true).build());
            List<Long> menuIds = iRoleMenus.stream().map(IRoleMenuDTO::getMenuId).distinct().collect(Collectors.toList());
            return iMenuService.selectPage(menuDTO,pageSize,pageNo,(iMenu, queryWrapper)->{
                queryWrapper.in(BaseFieldNames.CREATE_LOGIN_ID, beAuthLoginIds);
                queryWrapper.notIn(!CollectionUtils.isEmpty(menuIds),BaseFieldNames.ID,menuIds);
                String keyword = menuDTO.getKeyword();
                queryWrapper.and(StrUtil.isNotBlank(keyword),(wrapper)->{
                    wrapper.like("menu_name",keyword);
                    wrapper.or().like("menu_alias",keyword);
                });
            });
        }).orElse(result);
    }

    @Override
    public List<String> getMenuSignboard(String systemCode, CredentialDetail credentialDetail) {
        List<IMenuDTO> iMenus = iMenuService.selectList(IMenuDTO.builder().createSystemCode(systemCode).build(), (menu, queryWrapper) -> {
            if (Objects.nonNull(credentialDetail)) {
                List<Long> beAuthLoginIds = relevanceDesign.beAuthLoginIds(credentialDetail.getLoginId());
                queryWrapper.in(!CollectionUtils.isEmpty(beAuthLoginIds), BaseFieldNames.CREATE_LOGIN_ID, beAuthLoginIds);
            }
        });
        List<String> result = Arrays.asList(DefaultValues.IS_DEFAULT);
        if(!CollectionUtils.isEmpty(iMenus)){
            result = iMenus.stream().map(IMenuDTO::getMenuGroupSignboard).distinct().collect(Collectors.toList());
        }
        return result;
    }

    @Override
    public List<IMenuDTO> searchTreeMenus(String systemCode, String signboard, CredentialDetail credentialDetail) {
        List<IMenuDTO> menus = Collections.EMPTY_LIST;
        if(Objects.nonNull(credentialDetail)){
            Long loginId = credentialDetail.getLoginId();
            List<IRoleDTO> iRoles = roleCommandService.loginHasBindingRoles(IRoleDTO.builder().isEnable(true).build(), systemCode, loginId, loginId);
            if(!CollectionUtils.isEmpty(iRoles)){
                List<IRoleMenuDTO> relations = roleMenuService.selectList(IRoleMenuDTO.builder().build(), (roleMenu, queryWrapper) -> {
                    queryWrapper.in("role_id", iRoles.stream().map(IRoleDTO::getId).collect(Collectors.toList()));
                });
                if(!CollectionUtils.isEmpty(relations)){
                    menus = iMenuService.selectList(IMenuDTO.builder().menuGroupSignboard(signboard).createSystemCode(systemCode).isEnable(true).build(),
                            (menu, queryWrapper) -> {queryWrapper.in("id",
                                    relations.stream().map(IRoleMenuDTO::getMenuId).distinct().collect(Collectors.toList()));});
                }
            }
        }
        return menus;
    }

    @Override
    public List<IMenuDTO> searchOvertTreeMenus(String systemCode, String signboard) {
        Assert.notNull(systemCode,"系统编码不能为空");
        Assert.hasText(signboard,"菜单分组标识不能为空");
        List<IMenuDTO> enmptyMenus = Collections.EMPTY_LIST;
        return Optional.ofNullable(iRoleService.selectOne(IRoleDTO.builder().roleCode(SecurityQuantity.defaultRole)
                .createSystemCode(systemCode).build())).map(IRoleDTO::getId).map(id->{
            List<IMenuDTO> menus = iMenuService.selectList(IMenuDTO.builder().menuGroupSignboard(signboard)
                    .createSystemCode(systemCode).isEnable(true).build());
            if(CollectionUtils.isEmpty(menus)) return enmptyMenus;
            List<Long> menuIds = menus.stream().map(IMenuDTO::getId).collect(Collectors.toList());
            List<IRoleMenuDTO> iRoleMenus = roleMenuService.selectList(IRoleMenuDTO.builder().roleId(id).build(), (roleMenu, queryWrapper) -> {
                queryWrapper.in("menu_id",menuIds);
            });
            if(CollectionUtils.isEmpty(iRoleMenus)) return enmptyMenus;
            List<Long> filterMenuIds = iRoleMenus.stream().map(IRoleMenuDTO::getMenuId).distinct().collect(Collectors.toList());
            return menus.stream().filter(menu->filterMenuIds.contains(menu.getId())).collect(Collectors.toList());
        }).orElse(enmptyMenus);
    }

    private void checkPageQuery(IMenuDTO dto, Long pageNo, Long pageSize){
        Assert.notNull(dto,"菜单信息不能为空,请检查");
        Assert.notNull(dto.getCreateSystemCode(),"系统编码不能为空");
        Assert.notNull(pageNo,"页码不能为空");
        Assert.notNull(pageSize,"页大小不能为空");
    }
}
